package brickred.core
{
    import flash.display.Sprite;
    import flash.display.Stage;
    import flash.events.Event;
    import flash.geom.Rectangle;

    import away3d.core.managers.Stage3DProxy;
    import away3d.containers.View3D;
    import away3d.debug.AwayStats;
    import starling.core.Starling;
    import starling.display.Sprite;
    import starling.events.Event;

    import brickred.containers.Scene;
    import brickred.core.Application;
    import brickred.core.Logger;
    import brickred.events.DirectorEvent;
    import brickred.events.SceneEvent;

    public class Director extends flash.display.Sprite
    {
        private static var s_instance_:Director = null;
        private static var s_ready_:Boolean = false;

        private var stage3d_proxy_:Stage3DProxy;
        private var starling_:Starling;
        private var view_:View3D;
        private var current_scene_:Scene = null;

        private var stats_:AwayStats;

        public static function createInstance(app:Application,
            stage3d_proxy:Stage3DProxy, ready_callback:Function):void
        {
            if (s_instance_ != null) {
                return;
            }

            s_instance_ = new Director();
            app.addChild(s_instance_);
            s_instance_.init(stage3d_proxy);
            s_instance_.addEventListener(DirectorEvent.READY, ready_callback);
        }

        public static function getInstance():Director
        {
            if (!s_ready_) {
                return null;
            }
            return s_instance_;
        }

        public function Director()
        {
            if (s_instance_ != null) {
                throw new Error("call Director singleton constructor");
            }
        }

        private function init(stage3d_proxy:Stage3DProxy):void
        {
            stage3d_proxy_ = stage3d_proxy;

            starling_ = new Starling(starling.display.Sprite, stage,
                stage3d_proxy_.viewPort, stage3d_proxy_.stage3D);
            starling_.start();
            starling_.addEventListener(
                starling.events.Event.ROOT_CREATED, onStarlingRootCreated);

            view_ = new View3D();
            view_.stage3DProxy = stage3d_proxy_;
            view_.shareContext = true;
            stats_ = new AwayStats(view_);
            addChild(view_);
            addChild(stats_);

            addEventListener(flash.events.Event.ENTER_FRAME, onEnterFrame);
			stage.addEventListener(flash.events.Event.RESIZE, onResize);
        }

        private function onStarlingRootCreated(event:starling.events.Event):void
        {
            s_ready_ = true;
            dispatchEvent(new DirectorEvent(DirectorEvent.READY));
        }

        public function runScene(scene:Scene):void
        {
            var root:starling.display.Sprite =
                starling.display.Sprite(starling_.root);

            if (current_scene_ != null) {
                current_scene_.dispatchEvent(new SceneEvent(SceneEvent.REMOVED_FROM_STAGE));
                root.removeChild(current_scene_.getScene2D());
            }
            current_scene_ = scene;
            root.addChild(current_scene_.getScene2D());
            view_.scene = current_scene_.getScene3D();
            view_.camera = current_scene_.getCamera();
            current_scene_.dispatchEvent(new SceneEvent(SceneEvent.ADDED_TO_STAGE));
        }

        private function onEnterFrame(event:flash.events.Event):void
        {
            if (current_scene_ != null) {
                stage3d_proxy_.clear();
                current_scene_.dispatchEvent(new SceneEvent(SceneEvent.ENTER_FRAME));
                view_.render();
                starling_.nextFrame();
                stage3d_proxy_.present();
            }
        }

        private function onResize(event:flash.events.Event):void
        {
            stage3d_proxy_.width = stage.stageWidth;
            stage3d_proxy_.height = stage.stageHeight;
            starling_.stage.stageWidth = stage.stageWidth;
            starling_.stage.stageHeight = stage.stageHeight;
            view_.width = stage.stageWidth;
            view_.height = stage.stageHeight;

            if (current_scene_ != null) {
                current_scene_.dispatchEvent(new SceneEvent(SceneEvent.RESIZE));
            }
        }
    }
}

